package moe.dao.pool;

import java.io.Closeable;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;

public class PoolEntity<T> {
	private static ExecutorService threadPool =
			Executors.newCachedThreadPool(new ThreadFactory() {
				private int index = 0;

				public Thread newThread(Runnable r) {
					Thread result = new Thread(r);
					result.setDaemon(true);
					result.setName("Pool Reclaimer Thread-" + index++);
					return result;
				}

			});

	private Future future;
	private boolean timeout = false, inCore = false;
	private T object;

	PoolEntity(T obj, final Pool pool) {
		object = obj;
		future = threadPool.submit(new Runnable() {
			public void run() {
				checkTimeout(pool);
			}
		});
	}

	void checkout(Pool pool) {
		future.cancel(true);
		if (inCore) {
			pool.leaveCore();
		}
		if (!timeout && Proxy.isProxyClass(object.getClass())) {
			((Checkoutable) Proxy.getInvocationHandler(object)).checkout();
		}
	}

	private void checkTimeout(Pool pool) {
		try {
			Thread.sleep(pool.getAliveTimeout());
			if (pool.intoCore()) {
				inCore = true;
				Thread.sleep(pool.getCoreTimeout());
			}
		} catch (InterruptedException e) {
			return;
		}
		timeout = true;
		try {
			close(object);
			object = null;
		} catch (Exception e) {
			timeout = false;
			// ignore
		}
	}

	private void close(T object) throws Exception {
		if (object instanceof Closeable) {
			((Closeable) object).close();
		} else {
			Method method = object.getClass().getDeclaredMethod("close");
			method.setAccessible(true);
			method.invoke(object);
		}
	}

	void close() {
		future.cancel(true);
		if (!timeout) {
			try {
				close(object);
			} catch (Exception e) {
				// ignore
			}
		}
	}

	boolean isTimeout() {
		return timeout;
	}

	T get() {
		return object;
	}
}
